package com.xhb.campusservices.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.xhb.campusservices.common.lang.Result;
import com.xhb.campusservices.common.lang.ResultCode;
import com.xhb.campusservices.pojo.User;
import com.xhb.campusservices.pojo.userDto.ForgotMail;
import com.xhb.campusservices.pojo.userDto.Login;
import com.xhb.campusservices.pojo.userDto.ModifyPwd;
import com.xhb.campusservices.pojo.userDto.VerifyCode;
import com.xhb.campusservices.service.UserService;
import com.xhb.campusservices.util.JWTUtils;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import redis.clients.jedis.Jedis;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 登录管理
 */
@Slf4j
@RestController
@RequestMapping("/loginM")
public class LoginController {

    @Autowired
    UserService userService;

    @Autowired
    JavaMailSenderImpl mailSender;

    @Autowired
    JWTUtils jwtUtils;

    String host = "127.0.0.1";

    @Value("${upload.dir}")
    private String realPath;

    /**
     * 使用token来查询信息
     *
     * @return
     */
    @GetMapping("/tokenCS/{token}")
    public Result tokenCS(@PathVariable(name = "token") String token) {

        if (jwtUtils.isExpire(token)) {
            return Result.fail(403, "token已过期");
        }

        String userId = jwtUtils.getUserId(token);
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(User::getId, User::getUsername, User::getName, User::getPhone,
                User::getEmail, User::getSex, User::getBirthday, User::getPhoto, User::getState,
                User::getPermissions, User::getIsDeleted)
                .eq(User::getId, userId);
        User one = userService.getOne(queryWrapper);
        if (one == null) {
            return Result.fail("无效token");
        }
        return Result.succ(one);
    }


    /**
     * 注册
     * nginx -s reload
     *
     * @param num  验证码
     * @param user
     * @return
     */
    @PostMapping(value = {"/registered/{num}", "/registered"})
    public Result registered(@PathVariable(required = false) String num, @Validated @RequestBody User user) throws IOException {
        Jedis jedis = new Jedis(host, 6379);
        String codeKey = "EMAIL-" + user.getEmail();
        String redisCode = jedis.get(codeKey);
        log.info("验证码:[{}]", redisCode);
        if (num == null) {
            return Result.fail("验证码不能为空！");
        }
        if (redisCode == null) {
            return Result.fail("验证码已失效！");
        } else if (redisCode.equals(num)) {
            //查询账号是否重复
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getUsername, user.getUsername());
            User u = userService.getOne(queryWrapper);
            //如果user为空，则没有重复的账号，可以创建用户
            if (u == null) {
                //默认头像的地址
                String filePath = realPath + "default.jpg";
                MultipartFile headerImg = new MockMultipartFile("default.jpg", new FileInputStream(filePath));
                //设置新用户的默认头像
                String photo = user.getUsername() + ".jpg";
                headerImg.transferTo(new File(realPath + photo));
                //新用户的默认头像地址存进数据库
                user.setPhoto(photo);
                if (userService.save(user)) {
                    jedis.del(codeKey);
                    jedis.close();
                    return Result.succ(200, "注册成功", user);
                }
                return Result.fail("新增失败");
            }
            return Result.fail("账号已存在！");
        }
        return Result.fail("验证码错误");
    }

    /**
     * 注册验证码
     *
     * @return
     */
    @GetMapping("/sendMail/{email}")
    public Result sendMail(@PathVariable(name = "email") String email) {
        String numStr = getRandNumber();
        try {
            MimeMessage mimeMessage = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
            helper.setFrom("互助帮<2919858998@qq.com>");
            helper.setSubject("验证您的 互助帮 账号");
            helper.setText("<h2 style='display:inline'>互助帮</h2> 稳定、高速、方便地校园服务！<hr/>感谢您注册 互助帮，为了防止我们的服务被滥用，我们需要对您的电子邮件账号进行验证，" +
                    "您只需要在注册页面输入以下数字即可验证。验证码有效期为 2 分钟，请尽快完成注册。\n" + "<h3>" + numStr + "</h3> \n" +
                    "此邮件由系统自动发送，请勿直接回复，如果您没有注册过本站账号，请无视此邮件。<hr/> <p style='text-align:right'>互助帮</p>", true);
            //发送到这个邮箱
            helper.setTo(email);
            this.mailSender.send(mimeMessage);

            Jedis jedis = new Jedis(host, 6379);
            //把验证码放到redis,并设置2分钟过期时间
            String codeKey = "EMAIL-" + email;
            jedis.setex(codeKey, 120, numStr);
            jedis.close();
        } catch (MessagingException e) {
            e.printStackTrace();
        }
        return Result.succ(200, "验证码发送成功", null);
    }

    /**
     * 登录
     *
     * @param login
     * @param response 这里我们使用@Validated注解方式，如果实体不符合要求，系统会抛出异常，
     *                 那么我们的异常处理中就捕获到MethodArgumentNotValidException。
     * @return
     */
    @ApiOperation("登录")
    @PostMapping("/login")
    public Result login(@Validated @RequestBody Login login, HttpServletResponse response) {

        log.info("用户名:[{}]", login.getUsername());
        log.info("密码:[{}]", login.getPassword());
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        //页面输入的用户名判断是否是数据库里的数据
        queryWrapper.eq(User::getUsername, login.getUsername());
        User user = userService.getOne(queryWrapper);
        if (user == null) {
            return Result.fail(ResultCode.USER_NOT_EXIST, "用户不存在！");
        }
        if (!user.getPassword().equals(login.getPassword())) {
            return Result.fail(ResultCode.USER_ACCOUNT_ERROR, "密码不正确");
        }
        //生成JWT的令牌
        Map<String, String> map = new HashMap<>();
        map.put("userId", user.getId().toString());
        map.put("userName", user.getUsername());
        //响应token
        String token = jwtUtils.getToken(map);
        response.setHeader("Authorization", token);
        response.setHeader("Access-Control-Expose-Headers", "Authorization");
        return Result.succ(200, "登录成功", user, token);
    }

    /**
     * 忘记密码验证码
     *
     * @return
     */
    @PostMapping("/forgotMail")
    public Result forgotMail(@Validated @RequestBody ForgotMail forgotMail) {
        String numStr = getRandNumber();
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, forgotMail.getUsername());
        User user = userService.getOne(queryWrapper);
        //判断是否有该用户
        if (user == null) {
            return Result.fail(ResultCode.USER_NOT_EXIST, "用户不存在！");
        }
        //判断该用户的邮箱是否正确
        if (!user.getEmail().equals(forgotMail.getEmail())) {
            return Result.fail("账号为{" + forgotMail.getUsername() + "}的邮箱不正确！");
        }
        try {
            MimeMessage mimeMessage = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
            helper.setFrom("互助帮<2919858998@qq.com>");
            helper.setSubject("重设您的 互助帮 账号密码");
            helper.setText("<h2 style='display:inline'>互助帮</h2> 稳定、高速、方便地校园服务！<hr/><br>尊敬的 <b>" + user.getName() + "</b>:" +
                    "<p>您是否忘记了密码?</p>此验证码有效期为 2 分钟，请尽快完成修改。<h3>" + numStr + "</h3>" +
                    "<p>如果您不希望更改密码或并未请求更改密码，请忽略并删除该邮件。</p><p>谢谢!</p><hr/> <p style='text-align:right'>互助帮</p>", true);
            //发送到这个邮箱
            helper.setTo(forgotMail.getEmail());
            this.mailSender.send(mimeMessage);

            Jedis jedis = new Jedis(host, 6379);
            //把验证码放到redis,并设置2分钟过期时间
            String codeKey = "Forgot-" + forgotMail.getEmail();
            jedis.setex(codeKey, 120, numStr);
            jedis.close();
        } catch (MessagingException e) {
            e.printStackTrace();
        }
        return Result.succ(200, "验证码发送成功", null);
    }

    /**
     * 验证"忘记密码"验证码
     *
     * @param verifyCode
     * @return
     */
    @PostMapping("/verifyCode")
    public Result verifyCode(@Validated @RequestBody VerifyCode verifyCode) {
        Jedis jedis = new Jedis(host, 6379);
        String codeKey = "Forgot-" + verifyCode.getEmail();
        String redisCode = jedis.get(codeKey);
        log.info("验证码:[{}]", redisCode);

        //查询账号是否正确
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, verifyCode.getUsername())
                .eq(User::getEmail, verifyCode.getEmail());
        User u = userService.getOne(queryWrapper);

        //如果user为空，则账号不正确
        if (u == null) {
            return Result.fail("账号或邮箱输入异常");
        }

        if (redisCode == null) {
            return Result.fail("验证码已失效！");
        } else if (redisCode.equals(verifyCode.getVCode())) {
            jedis.del(codeKey);
            jedis.close();
            return Result.succ(200, "验证成功", u);
        }
        return Result.fail("验证码错误");
    }

    /**
     * 修改密码
     *
     * @return
     */
    @PostMapping("/modifyPwd")
    public Result modifyPwd(@Validated @RequestBody ModifyPwd modifyPwd) {
        if (!modifyPwd.getPwd().equals(modifyPwd.getRpwd())) {
            return Result.fail("两次密码不一致！");
        }
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getUsername, modifyPwd.getUsername())
                .eq(User::getEmail, modifyPwd.getEmail())
                .set(User::getPassword, modifyPwd.getPwd());
        if (userService.update(updateWrapper)) {
            return Result.succ(200, "密码修改成功", null);
        }
        return Result.fail("密码修改失败");
    }


    /**
     * 生成随机数
     *
     * @return
     */
    public static String getRandNumber() {
        StringBuffer numStr = new StringBuffer();
        int num;
        for (int i = 0; i < 6; i++) {
            // Math.random() 随机出0-1之间的实数，返回值是⼀个double 类型的
            num = (int) (Math.random() * 10);
            numStr.append(String.valueOf(num));
        }
        return numStr.toString();
    }
}
